// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MainViewModel.cs" company="XamlmNinja">
//   2010
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace ResumableDownload.ViewModel
{
    using System;
    using System.Linq;
    using System.Reactive.Linq;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Messaging;
    using Messages;
    using Microsoft.Phone.Shell;
    using WP7Contrib.Collections;
    using WP7Contrib.Communications;
    using WP7Contrib.Logging;
    using WP7Contrib.Services.DownloadManager;
    using WP7Contrib.Services.Navigation;

    public class MainViewModel : ViewModelBaseWp7
    {
        private readonly INetworkService networkService;

        private const string DownloadImages = @"\\downloads\images";
        private const string DownloadMp3 = @"\\downloads\mp3";
        private const string DownloadData = @"\\downloads\data";

        private FileRequest currentRequest;
        private NetworkType networkType;

        public MainViewModel(IDownloadService downloadService, INetworkService networkService, INavigationService navigationService, IMessenger messenger, ILog log)
            : base(navigationService, messenger, log)
        {
            this.networkService = networkService;
            this.DownloadService = downloadService;

            this.networkService.Status()
                .ObserveOnDispatcher()
                .Subscribe(network =>
                               {
                                   this.NetworkType = network;
                                   if (network == NetworkType.Wireless)
                                   {
                                       this.DownloadService.Settings.BlockSize = 32768;
                                   }
                                   else if (network == NetworkType.Ethernet)
                                   {
                                       this.DownloadService.Settings.BlockSize = 32768;
                                       //this.DownloadService.Settings.BlockSize = 262144;
                                   }

                                   this.RaisePropertyChanged("DownloadService");
                               });

            Observable.FromEventPattern<DownloaderStateEventArgs>(this.DownloadService, "DownloadStateChanged")
               .ObserveOnDispatcher()
               .Subscribe(args => this.HandleDownloaderStateChanged(args.EventArgs.State));

            Observable.FromEventPattern(this.DownloadService.Requests, "CollectionChanged")
              .ObserveOnDispatcher()
              .Subscribe(args => this.UpdateLists());
            
            Observable.FromEventPattern<FileRequestEventArgs>(this.DownloadService, "DownloadStarted")
               .ObserveOnDispatcher()
               .Subscribe(args => this.HandleDownloadUpdated(args.EventArgs.Request));

            Observable.FromEventPattern<FileRequestEventArgs>(this.DownloadService, "DownloadStopped")
               .ObserveOnDispatcher()
               .Subscribe(args => this.HandleDownloadUpdated());

            Observable.FromEventPattern<FileRequestEventArgs>(this.DownloadService, "DownloadUpdated")
              .ObserveOnDispatcher()
              .Subscribe(args => this.HandleDownloadUpdated(args.EventArgs.Request));

            Observable.FromEventPattern<FileRequestEventArgs>(this.DownloadService, "DownloadCompleted")
               .ObserveOnDispatcher()
               .Subscribe(args => this.HandleDownloadUpdated());

            Observable.FromEventPattern<FileRequestEventArgs>(this.DownloadService, "DownloadFailed")
              .ObserveOnDispatcher()
              .Subscribe(args => this.HandleDownloadFailed());

            this.StartCommand = new RelayCommand(() => this.DownloadService.Start());
            this.StopCommand = new RelayCommand(() => this.DownloadService.Stop());
            this.AddImageCommand = new RelayCommand(this.AddImage);
            this.AddMp3Command = new RelayCommand(this.AddMp3);
            this.AddLargeFileCommand = new RelayCommand(this.AddLargeFile);
            this.DeleteAllCommand = new RelayCommand(this.DeleteAll);
            
            PrimaryItemCommand = new RelayCommand<FileRequest>(this.Delete);
            SecondaryItemCommand = new RelayCommand<FileRequest>(this.Secondary);
            TertiaryItemCommand = new RelayCommand<FileRequest>(this.Tertiary);
        }
        
        public bool IsStartEnabled
        {
            get { return this.DownloadService.State == DownloaderState.Ready; }
        }

        public bool IsStopEnabled
        {
            get
            {
                var tmp = (this.DownloadService.State == DownloaderState.Starting ||
                           this.DownloadService.State == DownloaderState.Processing ||
                           this.DownloadService.State == DownloaderState.PausedNetwork ||
                           this.DownloadService.State == DownloaderState.PausedWaiting);

                return tmp;
            }
        }
        
        public IDownloadService DownloadService { get; private set; }

        public ReadOnlyObservableCollection<FileRequest> AllRequests
        {
            get { return this.DownloadService.Requests; }
        }

        public ReadOnlyObservableCollection<FileRequest> CompletedRequests
        {
            get { return new ReadOnlyObservableCollection<FileRequest>(this.DownloadService.Requests.Where(r => r.State == FileRequestState.Completed)); }
        }

        public ReadOnlyObservableCollection<FileRequest> FailedRequests
        {
            get { return new ReadOnlyObservableCollection<FileRequest>(this.DownloadService.Requests.Where(r => r.State == FileRequestState.Failed)); }
        }

        public ReadOnlyObservableCollection<FileRequest> PendingRequests
        {
            get { return new ReadOnlyObservableCollection<FileRequest>(this.DownloadService.Requests.Where(r => r.State == FileRequestState.NotStarted || r.State == FileRequestState.Started)); }
        }

        public FileRequest CurrentRequest
        {
            get
            {
                return this.currentRequest;
            }
            private set
            {
                this.currentRequest = value;
                this.RaisePropertyChanged("CurrentRequest");
                this.RaisePropertyChanged("CurrentIdentifier");
                this.RaisePropertyChanged("DownloadService");
            }
        }

        public NetworkType NetworkType
        {
            get
            {
                return this.networkType;
            }
            private set
            {
                this.SetPropertyAndNotify(ref this.networkType, value, "NetworkType");
            }
        }

        public string CurrentIdentifier
        {
            get { return this.currentRequest == null ? string.Empty : "Id: " + this.currentRequest.Identifier; }
        }
        
        public RelayCommand StartCommand { get; private set; }

        public RelayCommand StopCommand { get; private set; }

        public RelayCommand AddImageCommand { get; private set; }

        public RelayCommand AddMp3Command { get; private set; }

        public RelayCommand AddLargeFileCommand { get; private set; }

        public RelayCommand DeleteAllCommand { get; private set; }

        public static RelayCommand<FileRequest> PrimaryItemCommand { get; private set; }

        public static RelayCommand<FileRequest> SecondaryItemCommand { get; private set; }

        public static RelayCommand<FileRequest> TertiaryItemCommand { get; private set; }
        
        public override void Cleanup()
        {
            base.Cleanup();
        }
        
        private void AddImage()
        {
            var url = "http://farm7.static.flickr.com/6011/6000970117_945da95607_o.jpg";
            var filePath = DownloadImages + @"\6000970117_945da95607_o.jpg";

            FileRequest request = null;
            this.DownloadService.Add(url, filePath, ref request);
        }

        private void AddMp3()
        {
            var url = "http://dc195.4shared.com/img/712692926/4e7569b1/dlink__2Fdownload_2FV1ZktgBA_3Ftsid_3D20110805-71257-ad77cfa0/preview.mp3";
            var filePath = DownloadMp3 + @"\preview.mp3";

            FileRequest request = null;
            this.DownloadService.Add(url, filePath, ref request);
        }

        private void AddLargeFile()
        {
            var url = "http://go.microsoft.com/fwlink/?LinkID=220415";
            var filePath = DownloadData + @"\wpsdk71.iso";

            FileRequest request = null;
            this.DownloadService.Add(url, filePath, ref request);
        }

        private void DeleteAll()
        {
            this.DownloadService.RemoveAll();
            this.CurrentRequest = null;
        }

        private void HandleDownloadUpdated(FileRequest request)
        {
            this.CurrentRequest = request;
        }

        private void HandleDownloadUpdated()
        {
            this.CurrentRequest = null;
           
            this.UpdateLists();
        }

        private void HandleDownloadFailed()
        {
            if(this.currentRequest.Exception != null)
            {
                this.CurrentRequest = null;
            }

            this.UpdateLists();
        }

        private void HandleDownloaderStateChanged(DownloaderState state)
        {
            if (state == DownloaderState.PausedNetwork)
            {
                this.CurrentRequest = null;
            }
        }

        private void UpdateLists()
        {
            this.RaisePropertyChanged("AllRequests");
            this.RaisePropertyChanged("CompletedRequests");
            this.RaisePropertyChanged("FailedRequests");
            this.RaisePropertyChanged("PendingRequests");
        }

        private void Delete(FileRequest request)
        {
            this.DownloadService.Remove(request);
            this.UpdateLists();
        }

        private void Secondary(FileRequest request)
        {
            if (request.State == FileRequestState.Failed)
            {
                return;
            }
            
            var isImage = request.FilePath.ToLower().EndsWith(".jpg");
            if (isImage)
            {
                this.MessengerInstance.Send<SelectedImageMessage>(new SelectedImageMessage(request.FilePath));
                this.NavigationService.Navigate(new Uri("/View/ImagePage.xaml", UriKind.Relative));
                return;
            }

            var isMp3 = request.FilePath.ToLower().EndsWith(".mp3");
            if (isMp3)
            {
                this.MessengerInstance.Send<SelectedMp3Message>(new SelectedMp3Message(request.FilePath));
                this.NavigationService.Navigate(new Uri("/View/Mp3Page.xaml", UriKind.Relative));
                return;
            }
        }

        private void Tertiary(FileRequest request)
        {
            this.DownloadService.Prioritise(request);
        }
    }
}
